/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CPC_PAINBOT_ZONE_H
#define CPC_PAINBOT_ZONE_H

#include <QObject>
#include <QPointF>
#include <QSet>

class PositionBras;
/*! Zone de travail.
    Une zone de travail est définie par son centre, un rayon minimum et un rayon maximum.
    Si le rayon minimum est à 0, la zone est assimilable à un cercle. Autrement, il s'agit d'une
    couronne.
    Une zone connaît l'ensemble des points qui ont été utilisés. Elle permet également de trouver un
    point libre.
*/
class Zone : public QObject
{
    Q_OBJECT

    //! Centre de la zone de travail.
    Q_PROPERTY(QPointF centre READ centre WRITE setCentre)

    //! Rayon maximal de la zone de travail.
    Q_PROPERTY(qreal rayonMax READ rayonMax WRITE setRayonMax)

    //! Rayon minimal de la zone de travail.
    Q_PROPERTY(qreal rayonMin READ rayonMin WRITE setRayonMin)
public:
    //! Constructeur.
    explicit Zone(QObject *parent = 0);

    //! Centre de la zone.
    QPointF centre() const { return centre_; }

    //! Rayon maximal.
    qreal rayonMax() const { return rayonmax_; }
    //! Carré du rayon max.
    qreal rayonMax2() const { return rayonMax()*rayonMax(); }

    //! Rayon minimal.
    qreal rayonMin() const { return rayonmin_; }
    //! Carré du rayon min.
    qreal rayonMin2() const { return rayonMin()*rayonMin(); }

    /*! Indique si une position a été utilisée.
        Les critères retenus pour la position sont uniquement l'abscisse x et l'ordonnée y.

        \param[in] pos La position

        \retval true  La position a été utilisée
        \retval false La position n'a jamais été utilisée.
    */
    bool aEteUtilisee(const PositionBras &pos) const;

    /*! Indique si les coordonnées ont été utilisées.
        \param[in] x Abscisse
        \param[in] y Ordonnée

        \retval true  Les coordonnées ont déjà servi.
        \retval false Les coordonnées n'ont jamais servi.
    */
    bool ontEteUtilisees(qreal x, qreal y) const;

    /*! Trouve une position libre.
        \param[out] pos La position libre trouvée.
        \see positionLibre()
    */
    void positionLibre(PositionBras &pos);

    /*! Indique si les coordonnées sont dans la zone.
        \param[in] x abscisse
        \param[in] y ordonnée

        \retval true  Les coordonnées sont dans la zone.
        \retval false Les coordonnées n'appartiennent pas à la zone.
    */
    bool contient(qreal x, qreal y) const;

    /*! Indique si la position est dans la zone.
        \param[in] pos La position à contrôler.

        \retval true  La position est dans la zone.
        \retval false La position n'est pas dans la zone.

        \note Seules les composantes (x,y) sont prises en compte.
    */
    bool contient(const PositionBras &pos) const;

public slots:
    /*! Définit le centre.
        \param[in] centre Le nouveau centre de la zone.
        \note La liste des positions utilisées est remise à zéro.
    */
    void setCentre(const QPointF &centre) { centre_ = centre; utilisees_.clear(); }

    /*! Définit le rayon maximum.
        \param[in] rayon Le nouveau rayon max.
        \note La liste des positions utilisées est remise à zéro.
    */
    void setRayonMax(qreal rayon) { rayonmax_ = rayon; utilisees_.clear(); }

    /*! Définit le rayon minimum.
        \param[in] rayon Le nouveau rayon min.
        \note La liste des positions utilisées est remise à zéro.
    */
    void setRayonMin(qreal rayon) { rayonmin_ = rayon; utilisees_.clear(); }


protected:
    /*! Recherche des coordonnées libres.
        Recherche des coordonnées (x,y) libres dans le plan de la Zone.
        \param[out] x Abscisse
        \param[out] y Ordonnée
    */
    void chercherCoordonnees(qreal &x, qreal &y);
    QPointF centre_;          //!< Centre de la zone de travail.
    qreal rayonmax_;          //!< Rayon maximum dans lequel sont inscrits les points.
    qreal rayonmin_;          //!< Rayon minimum dans lequel les points s'inscrivent.
    QSet<QString> utilisees_; //!< Liste des positions déjà utilisées.
};
#endif // CPC_PAINBOT_ZONE_H
